import random
from . import game_data
from .girl_manager import girl_manager

#
# this is the data underlying a slave market
#
# the intention is to have more than one, 
# although the auction block in the Souk is the
# only one the initially accessible 
#
# different markets are going to have different
# characteristics. The souk has mainly low quality girls 
# and refreshes every 4 to 7 days. it never holds more
# than six girls and one or two are sold daily,
# starting with those of highest quality
#
# The J.Pettow and Son are toymakers in the Air Quarter
# who occasionally tinker with gynoids. Sometimes there are
# working models for sale, one, sometimes two,
# never more than three and frequently zero.
# Their stock has a low chance of changing daily.
# Only robot girls are traded at the Toyshop.
#
# Similarly, the Water Quarter has a house of Courtesans
# all highly trained, and capable healers and entertainers.
# None are for sale, although if the PC is of good repute
# and the girl is willing, delicate negotiations may be
# conducted. Similarly, the  fire quarter will sell
# gladiators and janissaries, while the Earth Quarter
# houses the richest slave traders (with the highest chance 
# of finding exotics or unique girls) and the Warrens
# Bazaar where the cities poorest are often sold into slavery
#
# That's probably too much configuration for command line args
# probably we're going to need sub-classes. Or just spend several
# lines initialising the instances
#

#
# Each market has a number of "slots" that can contain a girl
# Each slot has
#
#	* a chance to contain a unique girl 
#	* failing that a chance for a generic.
#	* a chance that a girl will remain unchanged on refresh
#	* a scaling factor applied to all a girl's stats
#	* a list of required traits (eg "robot girls only")
#	* a list of excluded traits (eg "no demons or undead")
#
class Slot(object):
	def __init__(self, *args, **kw):
		object.__init__(self)
#
#		we'll default this to the souk
#		so we have a slot with no chance at all of a unique
#		70% chance of a generic, and an 80% chance that
#		a girl already in the slot will remain rather than
#		be removed and possibly replaced
#
		self.unique	= kw.get("unique",  0.0)
		self.generic	= kw.get("generic", 0.7)
		self.persist	= kw.get("persist", 0.8)
#
#		I'd like a bit of variability in the quality.
#		this is a tad redundant, since the random girls all
#		(obviously) have random elements. Still, it'd be
#		nice to have a bit of range of quality beyond that/
#		so scaling takes a function. In this case a
#		lambda expression that averages out at about .4
#		but trails away in a normal distribution so that
#		in rare case the scaling can go as high as 1
#		or drop as low as zero.
#
#		(values <= 0 are capped at 0.05. Values > 1 can
#		stand, but the resulting stats still cap at 100.
#		so occasionally some higher than average girls 
#		will come through)
#
		func = lambda : .2 + random.normalvariate(1,1) / 5
		self.scaling = kw.get("scaling", func)
#
#		required and excluded traits
#
		self.required = kw.get("required", [])
		self.excluded = kw.get("excluded", [])
#
#		last but not least, a variable to hold the
#		girl instance in question
#
		self.girl = None

	def scale_factor(self):
		proto = self.scaling
		if isinstanc(proto, (int, float, long)):
			return 1.0 * proto
		if hasattr(proto, '__call__'):
			return proto()
		raise TypeError(
			"Slot.scaling should be either "
			"numeric or callable"
		)

#
#	check to see if the current slot occupant
#	remains there after the refresh
#
#	return True to stop refresh, false to
#	try and generate a new girl
#
	def persists(self):
#
#		no occupant
#
		if self.girl == None:
			return False
#
#		so there's a girl. does she persist?
#
		if random.random() < self.persist:
			return True		# yes
#
#		No, she does not. clear the slot
#		and ask for a new occupant
#
		self.girl = None
		return False

	def try_unique(self):
#
#		if chance is very small, don't bother
#
		if self.unique < 0.0001:
			return False
#
#		test the chance of getting a unique girl
#
		r = random.random()
		if r > self.unique:
			return False
		g = girl_manager.random_unique(
			excluding= self.excluded,
			requiring= self.required,
			slave    = "Always",
			virgin	 = "Never"
		)
		if g == None:
			return False
		self.girl = g
		return True

	def try_generic(self):
		r = random.random()
		if r > self.generic:
			return False
		self.girl = girl_manager.random_generic(
			excluding=self.excluded,
			requiring=self.required,
			slave    = "Always",
			virgin	 = "Never"
		)
		return True

	def refresh(self):
#
#		first order of business is to see if the
#		slot is occupied
#
		if self.persists():
			return
#
#		check for unique. 
#
		if self.try_unique():
			return
#
#		ok, try for a random girl
#
		self.try_generic()

class SlaveMarketBase(object):
	def __init__(self, *args, **kw):
		object.__init__(self)
#
#		next refresh is the day number
#
		self.next_refresh = -1
		self.slots = []
		self.count = 0
		self.refresh_min = 4
		self.refresh_max = 7
		# can't refresh here since slots are populated in 
		# subclass

	def refresh(self):
		data = game_data.data
		last_refresh = data.day
		next_refresh = data.day + random.randint(
			self.refresh_min,
			self.refresh_max + 1
		)
		for s in self.slots:
			s.refresh()

		l = self.slots
		self.slots = sorted(l, key=lambda x: (x.girl is None, x))

		#print "sorted: "
		#for s in self.slots:
		#	print s.girl
		#print ""
		l = self.slots + [ Slot() ]
		idx = next(i for i,j in enumerate(l) if j.girl == None)
		self.count = idx
		random.shuffle(self.slots[:self.count])

	def start_of_day(self):
		data = game_data.data
		if data.day == self.next_refresh:
			self.refresh()
			return
		self.check_sales()
	def check_sales(self):
		pass


class SlaveMarket_Souk(SlaveMarketBase):

	def __init__(self, *args, **kw):
		SlaveMarketBase.__init__(self, *args, **kw)

#
#		array of slots to hold the girls
#
		self.slots = [
#
#			first slot - 1 in 20 chance of a unique
#			100% chance of generic if no unique
#			100% scaling - this one is in good shape
#
			self.mk_slot(	unique	= 0.05,
					generic	= 1.0,
					scaling = 1.0,
			),
#
#			second slot - 1% chance of unique
#			100% generic, 70% scaling
#
			self.mk_slot(	unique	= 0.01,
					generic	= 1.0,
					scaling = 0.7,
			),
#
#			remaining slots, no chance of unique
#			diminishing chance of generics
#
			self.mk_slot(	generic = 0.8),
			self.mk_slot(	generic = 0.5),
			self.mk_slot(	generic = 0.3,
					scaling = 0.2
			),
			self.mk_slot(	generic = 0.1,
					scaling = 0.05
			),
		]
		self.refresh()

#
#	little func to make sure the exclusions get passed
#	to all slots
#
	def mk_slot(self, **kw):
		xs = [
			"Demon", "Gynoid", "Undead",
			"Not Human", "Construct",
			"No Souk"
		]
		return Slot(excluded=xs, **kw)

	def remove(self, girl):
		print "removing ", girl.name, " from market"
		lim = self.count
		self.count -= 1

		index = -1
		for i, slot in enumerate(self.slots):
			if slot.girl == girl:
				index = i
			if index == -1:
				continue
			if i+1 < lim:
				slot.girl = self.slots[i+1].girl
			else:
				slot.girl = None
		if self.slots[index].girl != None:
			return index
		return index - 1
			


		

slave_market_souk = SlaveMarket_Souk()

if __name__ == "__main__":
	market = slave_market_souk
	#print "souk market: {} girls".format(market.count)
	for slot in market.slots:
		if slot.girl == None:
			break
		#print slot.girl.name
		#slot.girl.print_()
		#print ""
